package zisu.netty.practice.RPC.client;


import zisu.netty.practice.RPC.client.proxy.RpcAsyncProxy;
import zisu.netty.practice.RPC.client.proxy.RpcProxyImpl;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Desc: ""
 * @Author: caixiang
 * @DATE: 2021/1/16 14:29
 */
public class RpcClient {

    private String serverAddress;

    private long timeout;

    private final Map<Class<?>,Object> syncProxyInstanceMap = new ConcurrentHashMap<>();
    private final Map<Class<?>,Object> asyncProxyInstanceMap = new ConcurrentHashMap<>();


    public void initClient(String serverAddress,long timeout){
        this.serverAddress = serverAddress;
        this.timeout = timeout;
        connect();
    }

    private void connect(){
        RpcConnectManager.getInstance().connect(serverAddress);
    }

    public void stop(){
        RpcConnectManager.getInstance().stop();
    }


    /**
     * 同步调用 方法。(只要)
     * @param interfaceClass
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T invokeSync(Class<T> interfaceClass){
//        Object o = Proxy.newProxyInstance(
//                //类加载器
//                interfaceClass.getClassLoader(),
//                new Class<?>[]{interfaceClass},
//                new RpcProxyImpl<>(interfaceClass,timeout));
        if(syncProxyInstanceMap.containsKey(interfaceClass)){
            return (T)syncProxyInstanceMap.get(interfaceClass);
        }
        //不存在的时候才需要重新new 一个。
        //注意Proxy 用的是 import java.lang.reflect.Proxy; 这个。
        Object proxy = Proxy.newProxyInstance(
                //loader: 用哪个类加载器去加载代理对象
                interfaceClass.getClassLoader(),
                //interfaces:动态代理类需要实现的接口
                new Class<?>[]{interfaceClass},
                //interfaceClass.getInterfaces(),

                //h:动态代理方法在执行时，会调用h里面的invoke方法去执行
                new RpcProxyImpl<>(interfaceClass, timeout)
        );
        syncProxyInstanceMap.put(interfaceClass,proxy);
        return (T) proxy;
    }

    /**
     * $invokeAsync 异步调用方式的方法
     * */
    public <T> RpcAsyncProxy invokeAsync(Class<T> interfaceClass){
        if(asyncProxyInstanceMap.containsKey(interfaceClass)){
            return (RpcAsyncProxy) asyncProxyInstanceMap.get(interfaceClass);
        }else {
            RpcProxyImpl<T> asyncProxyInstance = new RpcProxyImpl<>(interfaceClass, timeout);
            asyncProxyInstanceMap.put(interfaceClass,asyncProxyInstance);
            return asyncProxyInstance;
        }

    }
}